from enum import Enum

class RedisKey(object):
    """
    redis 各个变量名
    """
    taskinfo_save_setting = "taskinfo_save_setting"
    taskinfo = "taskinfo"
    cookie = "cookie"


class SQLTable(object):
    journal_list = "journal_list"
    journal_issue = "journal_issue"
    journal_volume = "journal_volume"
    journal_article = "journal_article"
    journal_home = "journal_home"
    taskinfo = "taskinfo"
    taskinfo_save_setting = "taskinfo_save_setting"
    err_analysis = "err_analysis"
    err_except_data = "err_except_data"
    # ########### paper
    paper_days = "paper_days"
    paper_page = "paper_page"
    paper_article = "paper_article"
    # 百科
    baike_home = "baike_home"
    baike_article = "baike_article"

    sub_db = "sub_db"
    # 政策
    policy_list = "policy_list"
    policy_article = "policy_article"
    # nssd
    nssd_list = "nssd_list"
    nssd_article = "nssd_article"
    # # medjournals
    # medjournals_years = "medjournals_years"
    # medjournals_issue = "medjournals_issue"
    # medjournals_article = "medjournals_article"
    # 其他
    other_list = "other_list"
    other_home = "other_home"
    other_sub_class = "other_sub_class"
    other_article = "other_article"
    other_article_spe = "other_article_spe"
    code_publisher = "code_publisher"


class CoreSqlValue(object):
    insert_ig_it = "insert ignore into"
    insert_it = "insert into"
    replace_it = "replace into"


class IsHasEnum(Enum):
    NORMAL = "normal"
    LATEST = "latest"


# class StateNode(object):
#     # 初始化一个节点
#     def __init__(self, node_type, val="", l_d_info=None):
#         if l_d_info is None:
#             l_d_info = []
#         self.node_type = node_type
#         self.val = val  # 节点值
#         self.l_d_info = l_d_info  # 其他信息，来自taskinfo 表的list
#         self.l_child = []  # 子节点列表
#
#     # 添加子节点
#     def add_child(self, node):
#         self.l_child.append(node)
#
#     def get_child(self):
#         return self.l_child
#
#     def get_l_d_info(self):
#         return self.l_d_info
#
#     def get_rsult(self, pm):
#         if self.node_type == "top":
#             for node in self.l_child:
#                 node.get_rsult(pm)
#             return True
#         elif self.node_type == "is_true":
#             lists = []
#             for node in self.l_child:
#                 lists.append(node.get_rsult(pm))
#             if all(lists) and lists:
#                 if self.val != "":
#                     pm.set_sql_state({self.val: 1}, is_update=True)
#             else:
#                 if self.val != "":
#                     pm.set_sql_state({self.val: 0}, is_update=True)
#         elif self.node_type == "state":
#             return self.get_state(pm)
#         else:
#             raise Exception("传入参数错误")
#
#     def get_state(self, pm):
#         pm_is_his = pm.get_is_his()
#         # keys为1_1 即 数据库taskinfo中的groups_ordernum
#         if all([eval(pm_is_his.get(it_d["keys"], "False")) for it_d in self.l_d_info]) and self.l_d_info:
#             pm.set_sql_state({self.val: 1}, is_update=True)
#             return True
#         else:
#             state = 0
#             is_sucess = True
#             state_dicts = {}
#             # 停止在这里面实现失败+1 在外面做 20210608
#             # update_no_placeholder = {}
#             for it_d in self.l_d_info:
#                 key_state = it_d["state_dicts"]["key_state"]
#                 # f_key = it_d["state_dicts"]["f_key"]
#                 # update_no_placeholder[f_key] = f_key + "+1"
#                 key = it_d["keys"]
#                 err_info = pm.get_down_err_info().get(key, None)
#                 state_dicts["err_msg"] = str(err_info)
#                 if err_info is not None and isinstance(err_info, dict):
#                     if err_info.get("code", 0) != 0:
#                         temp_state = int(err_info["code"])
#                         if str(temp_state) == "200":
#                             continue
#                         if str(temp_state) in key_state:
#                             # 表示状态码允许通过
#                             state = temp_state
#                         else:
#                             state = temp_state
#                             is_sucess = False
#                             break
#             state_dicts[self.val] = state
#             pm.set_sql_state(state_dicts, is_update=True)
#             # pm.set_update_no_placeholder(update_no_placeholder, is_update=True)
#             return is_sucess


class StateManager(object):
    """
    数据库状态管理器
    """

    def __init__(self):
        self.state_dicts = {}
        # 最终状态的bool值 由外面设置
        self.latest_state = False
        # 所有keys是否写入字典
        self.all_key_exist = False
        # 判定字典的状态是否为True
        self.keys_state = False
        self.k3 = []
        # 该标志表示程序获取了sql和redis，对后面做逻辑有帮助，理论上如果这个值为False是没办法打标的
        # 因为连sql的数据都没有加载进来就报错了
        self.sql_and_redis = False
        self.pm = None

    def set_pm_sql_and_redis(self, pm, is_state=True):
        self.sql_and_redis = is_state
        self.pm = pm

    def set_keys_state(self, keys, state_code, is_cover=False):
        """
        keys的值设置为列表，因为过程中可能有多个状态码值
        :param keys: keys 为 group + num的组合
        :param state_code:
         :param is_cover: 是否覆盖状态
        :return:
        """
        if keys in self.state_dicts.keys():
            if is_cover:
                self.state_dicts[keys] = [state_code]
            else:
                self.state_dicts[keys].append(state_code)
        else:
            self.state_dicts[keys] = [state_code]

    def is_keys_state(self, pm):
        """
        判断state_dicts字典的最终组合
        :return:
        """
        last_key_dicts = {}
        # 单个状态码的生成
        final_stat = ""
        for keys, lists in self.state_dicts.items():
            one_para = pm.redis_model.parse_dict[keys]
            state_key_dicts = eval(one_para.task_info.state_key)
            final_stat = one_para.task_set.final_stat
            # 获取数据库的state_key 里面的key_state
            key_state = state_key_dicts["key_state"]
            s_key = state_key_dicts["s_key"]
            last_key = state_key_dicts["last_key"]
            key_state_list = key_state.split(",")
            this_keys_state = 1
            key_is_ok = True
            # 如果列表里一条数据都没有，不能认为是成功
            if not lists:
                this_keys_state = 0
                key_is_ok = False
            for item in lists:
                # 如果存在在配置的允许通过的状态
                if str(item) in key_state_list:
                    # 配置里的状态码靠后有效
                    this_keys_state = int(item)
                    continue
                # 200状态码不算错误码
                elif str(item) == "200":
                    continue
                else:
                    key_is_ok = False
                    # 第一个状态码为我们需要打标的状态码
                    this_keys_state = int(item)
                    break

            pm.set_sql_state({s_key: this_keys_state}, is_update=True)
            if last_key in last_key_dicts.keys():
                last_key_dicts[last_key].append({"bools": key_is_ok, "this_keys_state": this_keys_state})
            else:
                last_key_dicts[last_key] = [{"bools": key_is_ok, "this_keys_state": this_keys_state}]
        # 生成最终状态码
        for key, lists in last_key_dicts.items():
            state = 1
            for item in lists:
                if item["bools"]:
                    continue
                else:
                    # 第一个异常状态码为最终状态的状态码
                    state = item["this_keys_state"]
                    break
            # key 可能为 空字符串，所以这里需要判定
            if key:
                pm.set_sql_state({key: int(state)}, is_update=True)
        if not (self.all_key_exist and self.latest_state):
            if final_stat in pm.sql_state.keys():
                if pm.sql_state[final_stat] == 1:
                    pm.set_sql_state({final_stat: 0}, is_update=True)

    def set_latest_state(self, state):
        """
        最终状态评定，如果不为True，即使前面的状态为正确的，其他步骤也可能有问题
        这个步骤由外面位置调用
        :param state: 布尔值
        :return:
        """
        self.latest_state = state

    def is_all_keys_exist(self, pm):
        """
        判断所有keys是否存在，防止中间步骤结束，有值没有进来
        :return:
        """

        key1 = pm.redis_model.parse_dict.keys()
        key2 = self.state_dicts.keys()
        self.key3 = key1 - key2
        if not self.key3:
            self.all_key_exist = True

    def set_err_msg(self, pm):
        """
        设置错误消息，这里会把所有的错误信息写进去，后面会考虑排除掉我们允许通过的状态码信息
        :param pm:
        :return:
        """
        err_info = pm.get_down_err_info()
        pm.set_sql_state({"err_msg": str(err_info)}, is_update=True)

    def set_state(self, pm):
        """
        调用这个，这里控制步骤
        :return:
        """
        self.is_all_keys_exist(pm)
        self.set_err_msg(pm)
        self.is_keys_state(pm)

    def debug_dicts(self, pm):
        """
        打印信息，方便逻辑梳理
        :param pm:
        :return:
        """
        dicts = {
            "all_code": self.state_dicts,
            "all_key_exist": self.all_key_exist,
            "key3": self.key3,
            "is_latest_state": self.latest_state,
            "sql_state": pm.get_sql_state()

        }
        print(dicts)

    def deal_my_task_failed(self, bools, err_info):
        """
        如果最后的my_task收到的bool值是失败，需要保底打标，保证不被打成成功
        :return:
        """

        def get_code(err_info):
            for k, v in err_info.items():
                if k == "msg_code" or k == "code":
                    code = int(v)
                    return code
                if isinstance(v, dict):
                    return get_code(v)
            return 0

        if self.sql_and_redis:
            if isinstance(err_info, dict):
                code = get_code(err_info)
                keys = list(self.pm.redis_model.parse_dict.keys())[0]
                final_stat = self.pm.redis_model.parse_dict[keys].task_set.final_stat
                return {final_stat: code}

        return {}
